import React, { useState, useRef, useEffect } from 'react';
import { Box } from '@mui/material';
import Canvas from '@metacell/geppetto-meta-ui/3d-canvas/Canvas';
import CameraControls from '@metacell/geppetto-meta-ui/camera-controls/CameraControls';
import {
  canvasBgDark,
  canvasBgLight,
  bgRegular,
} from '../../theme';
import { THEMES } from '../../constants';

const CANVAS_LIGHT = 'canvas-toolbar-btns-light';
const CANVAS_DARK = 'canvas-toolbar-btns-dark';

const SELECTION_COLOR = {
  r: 0,
  g: 0.8,
  b: 0.8,
  a: 1,
};

const DEFAULT_COLOR = {
  g: 0.5,
  b: 0.6,
  r: 1,
  a: 1,
};

interface CameraOptions {
  angle: number;
  near: number;
  far: number;
  baseZoom: number;
  position: { x: number; y: number; z: number };
  rotation: {
    rx: number;
    ry: number;
    rz: number;
    radius: number;
  };
  autoRotate: boolean;
  movieFilter: boolean;
  reset: boolean;
  cameraControls: {
    instance: typeof CameraControls;
    props: Record<string, any>;
  };
}

interface CanvasDataItem {
  visibility?: boolean;
  color: { r: number; g: number; b: number; a: number };
  instancePath: string;
  selected?: boolean;
}

interface NetPyNEInstantiatedProps {
  data?: CanvasDataItem[];
  selectInstances?: (data: any, selectedInstances: any) => void;
  theme?: string;
  [key: string]: any;
}

/**
 * NetPyNEInstantiated Component
 * 3D network visualization component using Geppetto Canvas
 */
const NetPyNEInstantiated: React.FC<NetPyNEInstantiatedProps> = ({
  data = [],
  selectInstances,
  theme,
  ...otherProps
}) => {
  const [cameraOptions, setCameraOptions] = useState<CameraOptions>({
    angle: 60,
    near: 10,
    far: 2000000,
    baseZoom: 1,
    position: { x: -97.349, y: 53.797, z: 387.82 },
    rotation: {
      rx: 0.051,
      ry: -0.192,
      rz: -0.569,
      radius: 361.668,
    },
    autoRotate: false,
    movieFilter: true,
    reset: false,
    cameraControls: {
      instance: CameraControls,
      props: {},
    },
  });

  const [canvasBtnCls, setCanvasBtnCls] = useState<string>(CANVAS_LIGHT);
  const canvasRef = useRef<any>(null);
  const lastCameraUpdateRef = useRef<any>(null);

  const updateBtnsWithTheme = (removeClass: string | null, addClass: string): void => {
    const element = document.getElementById('CanvasContainer_component');
    if (element) {
      if (removeClass) {
        element.classList.remove(removeClass);
      }
      element.classList.add(addClass);
      setCanvasBtnCls(addClass);
    }
  };

  useEffect(() => {
    // Update theme when it changes
    if (theme === THEMES.BLACK) {
      updateBtnsWithTheme(CANVAS_LIGHT, CANVAS_DARK);
    } else if (theme === THEMES.LIGHT) {
      updateBtnsWithTheme(CANVAS_DARK, CANVAS_LIGHT);
    }
  }, [theme]);

  const onSelection = (selectedInstances: any): void => {
    if (selectInstances) {
      selectInstances(data, selectedInstances);
    }
  };

  const mapToCanvasData = (inputData: CanvasDataItem[]): any[] => {
    return inputData.map((item) => ({
      visibility: item?.visibility !== undefined ? item.visibility : true,
      color: item.selected ? SELECTION_COLOR : item.color,
      instancePath: item.instancePath,
    }));
  };

  const canvasData = mapToCanvasData(data);

  let camOptions = cameraOptions;
  if (lastCameraUpdateRef.current) {
    camOptions = {
      ...cameraOptions,
      position: lastCameraUpdateRef.current.position,
      rotation: {
        ...lastCameraUpdateRef.current.rotation,
        radius: cameraOptions.rotation.radius,
      },
    };
  }

  const backgroundColor =
    theme === THEMES.BLACK
      ? canvasBgDark
      : theme === THEMES.LIGHT
      ? canvasBgLight
      : bgRegular;

  return (
    <Box
      sx={{
        height: '800px',
        width: '100%',
        display: 'flex',
        alignItems: 'stretch',
      }}
    >
      <Canvas
        data={canvasData}
        ref={canvasRef}
        key="CanvasContainer"
        cameraOptions={camOptions}
        backgroundColor={backgroundColor}
        onSelection={onSelection}
        linesThreshold="10000"
        renderingThreshold="2000"
        {...otherProps}
      />
    </Box>
  );
};

export default NetPyNEInstantiated;

